<script setup>
import { ref, reactive } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { getBangDevicedApi } from '@/services/device/device'
import ZeroLoading from '@/components/loading/loading-pulse.vue'

// 搜索到的蓝牙设备列表
const blueDeviceList = ref([])

// 弹出框
const inputDialog = ref()
// 关闭弹出框
const inputClose = ref()
// WiFi名称
const form = ref({
  ssid: '',
  psw: '',
})
const formRef = ref()
const dynamicRules = {
  ssid: {
    rules: [
      {
        required: true,
        errorMessage: '名称不能为空',
      },
    ],
  },
  psw: {
    rules: [
      {
        required: true,
        errorMessage: '密码不能为空',
      },
    ],
  },
}

// loading
const loading = ref(false)

onLoad(() => {
  initBlue()
  startWifi()
})

// 初始化蓝牙
const initBlue = () => {
  uni.openBluetoothAdapter({
    success(res) {
      loading.value = true
      console.log('初始化蓝牙成功')
      console.log(res)
      getBluetoothDevices()
      onBluetoothAdapterStateChange()
      discovery()
    },
    fail(err) {
      console.log('初始化蓝牙失败')
      uni.showToast({ icon: 'none', title: '请打开蓝牙' })
      console.error(err)
      return
    },
  })
}

const devicesId = ref('')
// 开始搜寻附近设备
const discovery = () => {
  uni.startBluetoothDevicesDiscovery({
    success(res) {
      console.log(res, '开始搜索')
      // 开启监听回调
      uni.onBluetoothDeviceFound((res) => {
        if (res.devices[0].name == 'BfCloud_MG04235200292') {
          devicesId.value = res.devices[0].deviceId
          connect(res.devices[0])
        }
      })
    },
    fail(err) {
      console.log('搜索失败')
      console.error(err)
    },
  })
}

// 获取已发现的蓝牙设备 包括 已经和本机处于连接状态的设备
const getBluetoothDevices = () => {
  uni.getBluetoothDevices({
    success(res) {
      if (res.devices[0]) {
        loading.value = false
        console.log(ab2hex(res.devices[0].advertisData), '已连接')
        uni.showToast({ icon: 'none', title: '您已绑定该设备，无需重复操作' })
      }
    },
    fail(err) {
      console.error(err)
    },
  })
}

// 监听本机蓝牙状态变化的事件
const onBluetoothAdapterStateChange = () => {
  uni.onBluetoothAdapterStateChange({
    success(res) {
      console.log('adapterState changed, now is', res)
    },
    fail(err) {
      console.log('changed失败')
      console.error(err)
    },
  })
}

// 蓝牙设备的id
let deviceId = ref('')
// 连接设备
const connect = (data) => {
  console.log(data, '连接设备')
  deviceId.value = data.deviceId

  uni.createBLEConnection({
    deviceId: deviceId.value,
    success(res) {
      console.log('连接成功')
      console.log(res, 'deviceId')
      // 停止搜索
      stopDiscovery()
      // 获取服务 拿到serviceId
      getServices()
    },
    fail(err) {
      console.log('连接失败')
      console.error(err)
      uni.showToast({
        title: '连接失败',
        icon: 'error',
      })
    },
  })
}

// 停止搜索
const stopDiscovery = () => {
  uni.stopBluetoothDevicesDiscovery({
    success(res) {
      console.log('停止成功')
      console.log(res)
    },
    fail(err) {
      console.log('停止失败')
      console.error(err)
    },
  })
}

let serviceId = ref('')
// 获取服务
const getServices = () => {
  setTimeout(() => {
    uni.getBLEDeviceServices({
      deviceId: deviceId.value,
      success(res) {
        if (res.services.length) {
          serviceId.value = res.services[0].uuid
        }
        // 获取特征值 拿到characteristicId
        getCharacteristics()
      },
      fail(err) {
        console.error(err)
      },
    })
  }, 2000)
}

let characteristicId0 = ref('')
let characteristicId1 = ref('')
// 获取特征值
const getCharacteristics = () => {
  setTimeout(() => {
    uni.getBLEDeviceCharacteristics({
      deviceId: deviceId.value,
      serviceId: serviceId.value,
      success(res) {
        console.log(res, 'characteristicId')
        if (res.characteristics.length) {
          characteristicId0.value = res.characteristics[0].uuid
          characteristicId1.value = res.characteristics[1].uuid
        }
        // 开启消息监听
        notify()
        // 获取连接wifi信息
        connectedWifi()
      },
      fail(err) {
        console.error(err)
      },
    })
  }, 1000)
}

// 开启消息监听
const notify = () => {
  uni.notifyBLECharacteristicValueChange({
    state: true,
    deviceId: deviceId.value, // 设备id
    serviceId: serviceId.value, // 监听指定的服务
    characteristicId: characteristicId0.value, // 监听对应的特征值
    success(res) {
      console.log(res, '已开启开启消息监听')
      listenValueChange()
    },
    fail(err) {
      console.error(err)
    },
  })
}
// ArrayBuffer转16进度字符串示例
const ab2hex = (buffer) => {
  const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
    return ('00' + bit.toString(16)).slice(-2)
  })
  return hexArr.join('')
}

// 将16进制的内容转成字符串
const hexCharCodeToStr = (hexCharCodeStr) => {
  var trimedStr = hexCharCodeStr.trim()
  var rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr
  var len = rawStr.length
  if (len % 2 !== 0) {
    alert('存在非法字符!')
    return ''
  }
  var curCharCode
  var resultStr = []
  for (var i = 0; i < len; i = i + 2) {
    curCharCode = parseInt(rawStr.substr(i, 2), 16)
    resultStr.push(String.fromCharCode(curCharCode))
  }
  return resultStr.join('')
}

// 监听到的内容
const message = ref('')
const messageHex = ref('') // 十六进制

// 监听消息变化
const listenValueChange = () => {
  uni.onBLECharacteristicValueChange((res) => {
    console.log(res)
    let resHex = ab2hex(res.value)
    console.log(resHex)
    messageHex.value = resHex
    let result = hexCharCodeToStr(resHex)
    console.log(String(result), '设备返回的数据')
    message.value = String(result)
  })
}

// 打开wifi模块
const startWifi = () => {
  uni.startWifi({
    success(res) {
      console.log(res)
    },
    fail(res) {
      console.log(res)
      uni.showToast({
        title: '请打开WIFI',
        icon: 'none',
        duration: 1000,
      })
    },
  })
}

// 获取连接wifi信息
const connectedWifi = () => {
  uni.getConnectedWifi({
    success: function (res) {
      loading.value = false
      form.value.ssid = res.wifi.SSID
      inputDialog.value.open()
      console.log(res, 'psw', form.value.psw)
    },
    fail: function (err) {
      console.log(err)
    },
  })
}

// 用户输入wifi账号密码
const inputChange = (e, val) => {
  if (val === 'ssid') {
    form.value.ssid = e
  } else {
    form.value.psw = e
  }
}

// 取消
const inputDialogClose = () => {
  inputDialog.value.close()
  form.value.ssid = ''
  form.value.psw = ''
}

// 提交
const submit = (val) => {
  formRef.value
    .validate()
    .then((res) => {
      send(form.value.ssid, form.value.psw)
      setTimeout(() => {
        // 关闭窗口后，恢复默认内容
        inputDialog.value.close()
        form.value.ssid = ''
        form.value.psw = ''
      }, 2000)
    })
    .catch((err) => {
      console.log('err', err)
    })
}

// 将十六进制字符串转换为 ArrayBuffer 格式的数据
function hexStringToArrayBuffer(hexString) {
  const bytes = new Uint8Array(
    hexString.match(/[\da-f]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    }),
  )
  return bytes.buffer
}

// 获取CRC8校验值函数
function getCRC8(data) {
  const crcTable = [
    0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
    0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
    0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
    0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
    0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
    0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
    0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
    0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
    0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
    0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
    0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
    0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
    0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
    0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
    0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
    0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
  ]

  let crc = 0x00
  for (let i = 0; i < data.length; i++) {
    crc = crcTable[(crc ^ data[i]) & 0xff]
  }

  return crc.toString(16).toUpperCase()
}

// 转16进制
const stringToHex = (str) => {
  let hex = ''
  for (let i = 0; i < str.length; i++) {
    hex += str.charCodeAt(i).toString(16).toUpperCase().padStart(2, '0') + ' '
  }
  return hex.trim()
}

// 向蓝牙设备发送指令
const send = (ssid, psw) => {
  const ssidHex = stringToHex(ssid)
  const pswHex = stringToHex(psw)
  const aa = `14 04 1C ${ssidHex} 1D ${pswHex}`

  const aaArray = aa.split(' ').map((hex) => parseInt(hex, 16))

  const crc = getCRC8(aaArray)

  // 向蓝牙设备发送指令
  let buff = `55 AA 14 04 1C ${ssidHex} 1D ${pswHex} ${crc} 1F`
  // 查询SN码指令
  // let buff = '55AA020200FC1F'
  const buffer = hexStringToArrayBuffer(buff) // 使用 stringToArrayBuffer 函数转换数据格式

  uni.writeBLECharacteristicValue({
    deviceId: deviceId.value,
    serviceId: serviceId.value,
    characteristicId: characteristicId1.value,
    value: buffer, // buffer 的格式为 ArrayBuffer
    success(res) {
      console.log('指令下发成功', res)
      // 断开蓝牙，发起蓝牙连接，接受配网结果
      uni.closeBLEConnection({
        deviceId: deviceId.value,
        success: (res) => {
          console.log('断开连接成功', res)
          setTimeout(() => {
            uni.createBLEConnection({
              deviceId: deviceId.value,
              success(res) {
                console.log('连接成功')
                console.log(res, 'deviceId')
              },
              fail(err) {
                console.log('连接失败')
                console.error(err)
                uni.showToast({
                  title: '连接失败',
                  icon: 'error',
                })
              },
            })
          }, 1000)
        },
        fail: (err) => {
          console.log('断开连接失败', err)
        },
      })

      // 设备绑定
      // bangDeviced(deviceNo.value)
      // uni.navigateTo({
      //   url: '/pagesMember/device/device',
      // })
    },
    fail(err) {
      console.log('指令发送失败', err)
    },
  })
}
// 绑定设备
// const bangDeviced = async (deviceId) => {
//   const res = await getBangDevicedApi({ deviceNo: deviceId })
//   console.log(res)
// }

// 11 读取数据
const read = () => {
  uni.readBLECharacteristicValue({
    deviceId: deviceId.value,
    serviceId: serviceId.value,
    characteristicId: characteristicId1.value,
    success(res) {
      console.log(res, '读取到的数据')
    },
    fail(err) {
      console.error(err)
    },
  })
}
</script>

<template>
  <view class="bindDevice">
    <zero-loading v-if="loading" type="pulse"></zero-loading>
    <uni-popup ref="inputDialog" type="dialog">
      <view class="dialog">
        <view class="title">连接wifi</view>
        <uni-forms ref="formRef" :rules="dynamicRules" :modelValue="form">
          <uni-forms-item label="名称" required name="ssid">
            <uni-easyinput v-model.trim="form.ssid" @change="inputChange($event, 'ssid')" />
          </uni-forms-item>
          <uni-forms-item label="密码" required name="psw">
            <uni-easyinput
              v-model.trim="form.psw"
              @change="inputChange($event, 'psw')"
              placeholder="请输入wifi密码"
            />
          </uni-forms-item>
          <view class="btns">
            <button type="default" size="mini" @click="inputDialogClose">取 消</button>
            <button type="primary" size="mini" @click="submit">提 交</button>
          </view>
        </uni-forms>
      </view>
    </uni-popup>
  </view>
</template>

<style scoped>
.bindDevice {
  height: 100vh;
  background-image: url('../../static/device/wl1.png');
  background-size: 100px 100px; /* 图像尺寸适应容器大小 */
  background-position: center; /* 图像在容器中居中显示 */
  background-repeat: no-repeat; /* 不重复平铺背景图像 */
}
.title {
  text-align: center;
  margin-bottom: 10px;
}
.dialog {
  width: 300px;
  height: 220px;
  padding: 20px;
  border-radius: 15px;
  background-color: #fff;
}
.btns {
  display: flex;
  justify-content: space-between;
}
</style>
